extern crate alloc;

use self::alloc::vec::Vec;
use core::alloc::Layout;
use cortex_m::asm;
use alloc_cortex_m::CortexMHeap;



#[inline]
pub fn heap_start() -> *mut u32 {
    extern "C" {
        static mut __sheap: u32;
    }

    unsafe { &mut __sheap }
}

pub fn init(heap_size:usize) {
	unsafe { ALLOCATOR.init(heap_start() as usize, heap_size) }
}

pub fn alloc(size:usize) -> OMem {
	let mut mem = Mem {vec:Vec::new()};
	if size > 0 {
		mem.vec.resize(size, 0);
	}
	Some(mem)
}

pub fn realloc(mem:&mut Mem, size:usize) {
	mem.vec.resize(size, 0);
}

pub type OMem = Option<Mem>;

#[derive(Clone)]
pub struct Mem {
	vec:Vec<u8>,
}

impl Mem {
	pub fn write(&mut self, a:&[u8]) {
		for i in 0..a.len() {
			if i >= self.vec.len() {
				panic!("mm out")
			}
			self.vec[i] = a[i];
		}
	}
	pub fn read(&self, offset:usize) -> u8 {
		self.vec[offset]
	}
}

#[global_allocator]
static ALLOCATOR: CortexMHeap = CortexMHeap::empty();

#[alloc_error_handler]
fn alloc_error(_layout: Layout) -> ! {
    asm::bkpt();

    loop {}
}


use utils::tprn;

//#[test_case]
pub fn test1() {
	tprn!("mm test s!");

	//init(1024);

	let mem = alloc(4);
	assert!(mem.is_some());

	let p = |m:&Mem| {
		tprn!("{:x} {:x} {:x} {:x}", m.read(0), m.read(1), m.read(2), m.read(3));
	};

	let mut mem = mem.unwrap();

	mem.write(&828_i32.to_be_bytes());
	p(&mem);
	assert_eq!(mem.read(0), b'\0');
	assert_eq!(mem.read(1), b'\0');
	assert_eq!(mem.read(2), b'\x03');
	assert_eq!(mem.read(3), b'\x3c');

	realloc(&mut mem, 16);
	mem.write(b"abcdefghijk");
	p(&mem);
	assert_eq!(mem.read(0), b'\x61');
	assert_eq!(mem.read(1), b'\x62');
	assert_eq!(mem.read(2), b'\x63');
	assert_eq!(mem.read(3), b'\x64');

	tprn!("mm test e!");
}
